﻿namespace NetFx.SMIL.References
{
  using System;
  using System.Text;
  using System.Collections;
  using System.Collections.Generic;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using System.Security;
  using System.Security.Permissions;

  using NetFx.MSIL;

  /// <summary>
  /// 不清晰的成员匹配异常。
  /// </summary>
  [Serializable]
  public class AmbiguousMemberMatchesException : System.Exception
  {
    #region Fields
    protected MemberInfo[] allMatches = null;
    #endregion
    #region Properties
    public virtual MemberInfo[] AllMatches
    {
      get
      {
        return this.allMatches;
      }
    }
    #endregion
    #region Constructors
    public AmbiguousMemberMatchesException() { }
    public AmbiguousMemberMatchesException(string message) : base(message) { }
    public AmbiguousMemberMatchesException(string message, System.Exception inner) : base(message, inner) { }
    public AmbiguousMemberMatchesException(string message, params MemberInfo[] allMatches) : base(message) { this.allMatches = allMatches; }
    protected AmbiguousMemberMatchesException(
      System.Runtime.Serialization.SerializationInfo info,
      System.Runtime.Serialization.StreamingContext context)
      : base(info, context) { }
    #endregion
  }

  /// <summary>
  /// 对成员的引用。
  /// </summary>
  public abstract class MemberRef:ReflectRef
  {
    #region Consts
    public const BindingFlags AllAccessFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
    /// <summary>
    /// 命名空间标识符分隔符。
    /// </summary>
    public const char NamespaceSeparator = '.';
    /// <summary>
    /// 嵌套类标识符分隔符。
    /// </summary>
    public const char NestingTypeSeparator = '+';

    public const string MemberSeparator = "::";
    #endregion
    #region Statics
    /// <summary>
    /// 获取成员对应的引用。
    /// </summary>
    /// <param name="identifier">成员的完全限定名。</param>
    /// <returns>对应的引用。</returns>
    /// <remarks>
    /// 推荐使用GetMemberRef方法而不是此方法。
    /// 因为获取成员引用还需要其他的信息，
    /// 例如绑定标志和所在程序集等。
    /// </remarks>
    public static MemberRef of(QualifiedIdentifier identifier)
    {
      return GetMemberRef(identifier, false, false,AllAccessFlags,Assembly.GetCallingAssembly());
    }
    /// <summary>
    /// 获取成员对应的引用。
    /// </summary>
    /// <param name="memberInfo">成员信息。</param>
    /// <returns>对应的引用。</returns>
    public static MemberRef of(MemberInfo memberInfo)
    {
      if (memberInfo != null)
      {
        if (memberInfo is FieldInfo)
        {
          return FieldRef.of(memberInfo as FieldInfo);
        }
        else if (memberInfo is Type && ((Type)memberInfo).IsEnum)
        {
          return EnumRef.of(memberInfo as Type);
        }
        else if (memberInfo is EventInfo)
        {
          return EventRef.of(memberInfo as EventInfo);
        }
        else if (memberInfo is MethodBase)
        {
          return MethodRef.of(memberInfo as MethodBase);
        }
        else if (memberInfo is PropertyInfo)
        {
          return PropertyRef.of(memberInfo as PropertyInfo);
        }
        else if (memberInfo is Type)
        {
          return TypeRef.of(memberInfo as Type);
        }
      }
      return null;
    }
    /// <summary>
    /// 获取成员名称（全名）。
    /// </summary>
    /// <param name="memberInfo">成员信息。</param>
    /// <param name="namespacePrefix">返回命名空间前缀长度（不包括结尾的点）。</param>
    /// <param name="classpacePrefix">返回类嵌套前缀长度（不包括结尾的点）。</param>
    /// <returns>返回成员全名。</returns>
    public static string GetMemberName(MemberInfo memberInfo, ref int namespacePrefix, ref int classpacePrefix)
    {
      if (memberInfo != null)
      {
        if (memberInfo.DeclaringType != null)
        {
          string memberName = memberInfo.Name;
          string declaringTypeShortName = memberInfo.DeclaringType.Name;
          string declaringTypeFullName = memberInfo.DeclaringType.FullName;

          int firstPlus = declaringTypeFullName.IndexOf(NestingTypeSeparator);

          if (firstPlus >= 0) //MANY NESTING TYPE LEVELS
          {
            //Type中存在Namespace属性，可以考虑直接使用Namespace属性而不用自己处理。
            int lastDot = declaringTypeFullName.LastIndexOf(NamespaceSeparator, firstPlus);

            namespacePrefix = (lastDot >= 0) ? lastDot : 0;

            classpacePrefix = (firstPlus >= 0) ? (declaringTypeFullName.Length - namespacePrefix - 1) : 0;
          }
          else //ONLY ONE NESTING TYPE LEVEL
          {
            namespacePrefix = declaringTypeFullName.LastIndexOf(
              NamespaceSeparator,
              declaringTypeFullName.Length - declaringTypeShortName.Length);
            classpacePrefix = declaringTypeShortName.Length;
          }

          return memberInfo != null ?
            declaringTypeFullName.Replace(
                NestingTypeSeparator,
                NamespaceSeparator
              )
              + NamespaceSeparator
              + memberName :
            string.Empty;
        }
        else if (memberInfo is Type) //MUST BE A TOPLEVEL TYPE!
        {
          string fullname = (memberInfo as Type).FullName;

          int lastDot = fullname.LastIndexOf(NamespaceSeparator);
          namespacePrefix = (lastDot >= 0) ? lastDot : 0;
          classpacePrefix = 0;

          return fullname;
        }
        else
        {
          return memberInfo.Name;
        }
      }
      return null;
    }
    /// <summary>
    /// 获取成员的引用。
    /// </summary>
    /// <param name="identifier">成员的完全限定名。</param>
    /// <param name="ignoreTypeCase">忽略类型大小写。</param>
    /// <param name="throwOnAmbiguous">在出现多个匹配时掷出异常。</param>
    /// <param name="bindingFlags">绑定标志。</param>
    /// <param name="assemblies">需要查询的程序集。</param>
    /// <returns>名称对应的成员引用。</returns>
    public static MemberRef GetMemberRef(QualifiedIdentifier identifier,bool ignoreTypeCase, bool throwOnAmbiguous, BindingFlags bindingFlags,params Assembly[] assemblies)
    {
      MemberInfo[] members = FindMemberInfo(identifier,ignoreTypeCase,bindingFlags,assemblies);
      if (members != null)
      {
        if (members.Length == 0)
        {
          return null;
        }
        else if (members.Length == 1)
        {
          return of(members[0]);
        }
        else if (members.Length > 1 )
        {
          if (throwOnAmbiguous)
            throw new AmbiguousMemberMatchesException(members.Length + " entries found about " + identifier.ToString(),members);
        }
      }
      return null;
    }
    /// <summary>
    /// 获取成员信息。
    /// </summary>
    /// <param name="reference">成员引用。</param>
    /// <param name="ignoreTypeCase">忽略类型大小写。</param>
    /// <param name="bindingFlags">绑定标志。</param>
    /// <param name="assemblies">需要查询的程序集。</param>
    /// <returns>成员信息。</returns>
    /// <remarks>
    /// 此方法识别MethodRef。
    /// 即，此方法可以对重载的Method进行区分。
    /// </remarks>
    public static MemberInfo[] FindMemberInfo(MemberRef memberRef, bool ignoreTypeCase, BindingFlags bindingFlags, Assembly[] assemblies)
    {
      MemberInfo[] members = (memberRef != null) ?
        FindMemberInfo(
          memberRef.Name,
          memberRef.NamespacePrefix,
          memberRef.ClassPrefix,
          ignoreTypeCase,
          bindingFlags,
          assemblies) :
        null;

      if (members != null && members.Length !=0)
      {
        if (members.Length > 1 && memberRef is MethodRef)
        {
          MethodRef methodRef = memberRef as MethodRef;

          List<MemberInfo> accepted = new List<MemberInfo>();
          foreach (MemberInfo member in members)
          {
            if (methodRef.IsMethodRefOf(member as MethodBase))
            {
              accepted.Add(member);
            }
          }
          return accepted.ToArray();
        }
      }

      return members;
    }
    /// <summary>
    /// 获取成员信息。
    /// </summary>
    /// <param name="identifier">标识符。</param>
    /// <param name="ignoreTypeCase">忽略类型大小写。</param>
    /// <param name="bindingFlags">绑定标志。</param>
    /// <param name="assemblies">需要查询的程序集。</param>
    /// <returns>成员信息。</returns>
    public static MemberInfo[] FindMemberInfo(QualifiedIdentifier identifier, bool ignoreTypeCase, BindingFlags bindingFlags, Assembly[] assemblies)
    {
      if (identifier != null)
      {
        if (assemblies == null) assemblies = new Assembly[] { Assembly.GetCallingAssembly(), Assembly.GetExecutingAssembly(), Assembly.GetEntryAssembly() };

        string[] scopes = identifier.NaturalScopes;
        if (scopes.Length > 0)
        {
          List<Type> containerTypes = new List<Type>();
          //First: Treat identifier as pure type.
          for (int c = scopes.Length; c >= 0; c--)
          {
            string typeName = CreateTypeNameOf(scopes, c);
            containerTypes.AddRange(FindType(typeName, ignoreTypeCase, assemblies));
          }

          if (containerTypes.Count > 0)
          {
            return (MemberInfo[])(containerTypes.ToArray());
          }
          else
          {
            containerTypes.Clear();

            string name = scopes[scopes.Length - 1];
            string[] typeScopes = new string[scopes.Length - 1];

            Array.Copy(scopes, typeScopes, typeScopes.Length);

            //Second: Separate the last name as memberName
            for (int c = scopes.Length; c >= 0; c--)
            {
              string typeName = CreateTypeNameOf(typeScopes, c);
              containerTypes.AddRange(FindType(typeName, ignoreTypeCase, assemblies));
            }

            scopes = null;
            typeScopes = null;

            if (containerTypes.Count > 0)
            {
              List<MemberInfo> members = new List<MemberInfo>();

              MemberInfo[] membersfound = null;
              foreach (Type type in containerTypes)
              {
                membersfound = type.GetMember(name, bindingFlags);
                if (membersfound != null)
                {
                  members.AddRange(membersfound);
                }
              }
              containerTypes.Clear();
              containerTypes = null;

              return members.ToArray();
            }
            else
            {
              return null;
            }
          }
        }
      }
      return null;
    }
    
    protected static MemberInfo[] FindMemberInfo(string name, string namespacePrefix, string classPrefix, bool ignoreTypeCase, BindingFlags bindingFlags, Assembly[] assemblies)
    {

      string typeName = string.Empty;

      if (assemblies == null) assemblies = new Assembly[] { Assembly.GetCallingAssembly(), Assembly.GetExecutingAssembly(), Assembly.GetEntryAssembly() };

      if (string.IsNullOrEmpty(namespacePrefix) && string.IsNullOrEmpty(classPrefix))
      {
        typeName = name;
      }
      else if (string.IsNullOrEmpty(namespacePrefix))
      {
        typeName = namespacePrefix + NamespaceSeparator + name;
      }
      else if (string.IsNullOrEmpty(classPrefix))
      {
        typeName = namespacePrefix;
      }
      else
      {
        typeName = namespacePrefix + NamespaceSeparator + classPrefix;
      }

      if (assemblies != null)
      {
        List<Type> containerTypes = FindType(typeName, ignoreTypeCase, assemblies);

        if (containerTypes.Count == 1)
        {
          return (MemberInfo[])containerTypes.ToArray(); //Found!
        }
        else
        {
          List<MemberInfo> members = new List<MemberInfo>();

          MemberInfo[] membersfound = null;
          foreach (Type type in containerTypes)
          {
            membersfound = type.GetMember(name, bindingFlags);
            if (membersfound != null)
            {
              members.AddRange(membersfound);
            }
          }
          return members.ToArray();
        }
      }
      return null;
    }
    
    protected static string CreateTypeNameOf(string[] scopes, int ubound)
    {
      int i = 0;
      StringBuilder strBuilder = new StringBuilder();

      for (i = 0; i <= ubound; i++)
      {
        strBuilder.Append(scopes[i]);
        strBuilder.Append(NamespaceSeparator);
      }

      for (; i < scopes.Length; i++)
      {
        strBuilder.Append(scopes[i]);
        strBuilder.Append(NestingTypeSeparator);
      }

      return strBuilder.ToString().TrimEnd(NamespaceSeparator, NestingTypeSeparator);
    }

    protected static List<Type> FindType(string typeName, bool ignoreTypeCase, Assembly[] assemblies)
    {
      List<Type> containerTypes = new List<Type>();
     
      if (assemblies == null) assemblies = new Assembly[] { Assembly.GetCallingAssembly(), Assembly.GetExecutingAssembly(), Assembly.GetEntryAssembly() };

      foreach (Assembly assembly in assemblies)
      {
        if (assembly != null)
        {
          containerTypes.AddRange(FindType(typeName, ignoreTypeCase, assembly.GetModules(true)));
        }
      }
      return containerTypes;
    }
    protected static List<Type> FindType(string typeName, bool ignoreTypeCase, Module[] modules)
    {
      Type curType = null;
      List<Type> containerTypes = new List<Type>();

      foreach (Module module in modules)
      {
        if (module != null)
        {
          curType = module.GetType(typeName, ignoreTypeCase);
          if (curType != null)
          {
            containerTypes.Add(curType);
          }
        }
      }
      return containerTypes;
    }
    #endregion
    #region Fields
    /// <summary>
    /// 程序集名称。
    /// </summary>
    //protected string assemblyName = 0;
    /// <summary>
    /// 命名空间前缀长度。
    /// </summary>
    protected int namespacePrefixCount = 0;
    /// <summary>
    /// 类嵌套前缀的长度。
    /// </summary>
    protected int classPrefixCount = 0;
    /// <summary>
    /// 成员所在模块的引用。
    /// </summary>
    protected ModuleRef moduleRef = null;
    #endregion
    #region Properties
    /// <summary>
    /// 获取引用类型（为成员）。
    /// </summary>
    public override DefType ReflectionType
    {
      get { return DefType.Member; }
    }
    /// <summary>
    /// 获取反射信息。
    /// </summary>
    public virtual MemberInfo MemberInfo
    {
      get
      {
        return this.referenced as MemberInfo;
      }
    }
    public virtual MemberInfo ReflectInfo
    {
      get
      {
        return this.MemberInfo;
      }
    }
    public override bool HasReflectInfo
    {
      get
      {
        return this.ReflectInfo != null;
      }
    }

    /// <summary>
    /// 获取成员的名字。
    /// </summary>
    public virtual string Name
    {
      get
      {
        int startIndex = (namespacePrefixCount > 0) ? namespacePrefixCount + 1 : 0;
        startIndex += (classPrefixCount > 0) ? classPrefixCount + 1 : 0;
        return identifier.Substring(startIndex);
      }
    }
    /// <summary>
    /// 获取命名空间前缀。
    /// </summary>
    public virtual string NamespacePrefix
    {
      get
      {
        return identifier.Substring(0, namespacePrefixCount);
      }
    }
    /// <summary>
    /// 获取类前缀。
    /// </summary>
    public virtual string ClassPrefix
    {
      get
      {
        return identifier.Substring(namespacePrefixCount + 1, classPrefixCount);
      }
    }
    /// <summary>
    /// 获取成员的限定名。
    /// </summary>
    public virtual QualifiedIdentifier MemberIdentifier
    {
      get
      {
        return References.QualifiedIdentifier.CreateIdentifierOf(NamespaceSeparator, this.identifier);
      }
    }
    /// <summary>
    /// 获取相关的模块。
    /// </summary>
    public virtual ModuleRef Module
    {
      get
      {
        return this.moduleRef;
      }
    }
    #endregion
    #region Constructors
    public MemberRef(MemberInfo memberInfo):base(String.Empty)
    {
      if (memberInfo != null)
      {
        this.identifier = GetMemberName(memberInfo, ref this.namespacePrefixCount, ref this.classPrefixCount);
        this.Bind(memberInfo);
      }
    }
    public MemberRef() : base() { }
    public MemberRef(string identifier) : this(identifier, 0, 0) { }
    protected MemberRef(string identifier, int namespacePrefixCount) : this(identifier, namespacePrefixCount, 0) { }
    protected MemberRef(string identifier, int namespacePrefixCount, int classPrefixCount)
      : base(identifier)
    {
      this.namespacePrefixCount = namespacePrefixCount;
      this.classPrefixCount = classPrefixCount;
    }
    #endregion
    #region Methods
    public override string ToString()
    {
      return this.HasReflectInfo ? this.GetFullName() : this.Identifier;
    }

    public virtual string GetFullName()
    {
      string fullname = this.Identifier;
      MemberInfo mi = this.ReflectInfo;
      if (mi != null)
      {
        Type declType = mi.DeclaringType;
        if (declType != null)
        {
          fullname = string.Format("{0}{1}{2}", declType.FullName, MemberSeparator, mi.Name);
        }
      }
      return fullname;
    }


    public override bool IsReferenceOf(object source)
    {
      if (source is MemberInfo)
      {
        bool bSame = false;

        using (MemberRef mRef = MemberRef.of(source as MemberInfo))
        {
          bSame = this.Equals(mRef);
        }

        return bSame;
      }
      return base.IsReferenceOf(source);
    }
    protected override void Dispose(bool disposing)
    {
      if (disposing)
      {
        this.DisposeModuleRef();
      }
      base.Dispose(disposing);
    }
    protected override ReflectRef OnBinding(object source)
    {
      System.Reflection.MemberInfo mInfo = source as System.Reflection.MemberInfo;
      if (mInfo != null)
      {
        this.DisposeModuleRef();
        this.moduleRef = ModuleRef.of(mInfo.Module);
      }
      return base.OnBinding(mInfo);
    }
    protected override ReflectRef OnBreaking(object referenced)
    {
      if (this.Module != null)
      {
        this.Module.Break();
      }
      return base.OnBreaking(referenced);
    }
    protected virtual void DisposeModuleRef()
    {
      if (this.moduleRef != null && !this.moduleRef.IsDisposed)
      {
        this.moduleRef.Dispose();
      }
      this.moduleRef = null;
    }
    #endregion
    #region Overrides for Modules
    /// <summary>
    /// 获取成员的引用。
    /// </summary>
    /// <param name="identifier">成员的完全限定名。</param>
    /// <param name="ignoreTypeCase">忽略类型大小写。</param>
    /// <param name="throwOnAmbiguous">在出现多个匹配时掷出异常。</param>
    /// <param name="bindingFlags">绑定标志。</param>
    /// <param name="assemblies">需要查询的程序集。</param>
    /// <returns>名称对应的成员引用。</returns>
    public static MemberRef GetMemberRef(QualifiedIdentifier identifier, bool ignoreTypeCase, bool throwOnAmbiguous, BindingFlags bindingFlags,params Module[] modules)
    {
      MemberInfo[] members = FindMemberInfo(identifier, ignoreTypeCase, bindingFlags, modules);
      if (members != null)
      {
        if (members.Length == 0)
        {
          return null;
        }
        else if (members.Length == 1)
        {
          return of(members[0]);
        }
        else if (members.Length > 1)
        {
          if (throwOnAmbiguous)
            throw new AmbiguousMemberMatchesException(members.Length + " entries found about " + identifier.ToString(), members);
        }
      }
      return null;
    }
    /// <summary>
    /// 获取成员信息。
    /// </summary>
    /// <param name="reference">成员引用。</param>
    /// <param name="ignoreTypeCase">忽略类型大小写。</param>
    /// <param name="bindingFlags">绑定标志。</param>
    /// <param name="assemblies">需要查询的程序集。</param>
    /// <returns>成员信息。</returns>
    /// <remarks>
    /// 此方法识别MethodRef。
    /// 即，此方法可以对重载的Method进行区分。
    /// </remarks>
    public static MemberInfo[] FindMemberInfo(MemberRef memberRef, bool ignoreTypeCase, BindingFlags bindingFlags, Module[] modules)
    {
      MemberInfo[] members = (memberRef != null) ?
        FindMemberInfo(
          memberRef.Name,
          memberRef.NamespacePrefix,
          memberRef.ClassPrefix,
          ignoreTypeCase,
          bindingFlags,
          modules) :
        null;

      if (members != null && members.Length != 0)
      {
        if (members.Length > 1 && memberRef is MethodRef)
        {
          MethodRef methodRef = memberRef as MethodRef;

          List<MemberInfo> accepted = new List<MemberInfo>();
          foreach (MemberInfo member in members)
          {
            if (methodRef.IsMethodRefOf(member as MethodBase))
            {
              accepted.Add(member);
            }
          }
          return accepted.ToArray();
        }
      }

      return members;
    }
    /// <summary>
    /// 获取成员信息。
    /// </summary>
    /// <param name="identifier">标识符。</param>
    /// <param name="ignoreTypeCase">忽略类型大小写。</param>
    /// <param name="bindingFlags">绑定标志。</param>
    /// <param name="assemblies">需要查询的程序集。</param>
    /// <returns>成员信息。</returns>
    public static MemberInfo[] FindMemberInfo(QualifiedIdentifier identifier, bool ignoreTypeCase, BindingFlags bindingFlags, Module[] modules)
    {
      if (identifier != null)
      {
        string[] scopes = identifier.NaturalScopes;
        if (scopes.Length > 0)
        {
          List<Type> containerTypes = new List<Type>();
          //First: Treat identifier as pure type.
          for (int c = scopes.Length; c >= 0; c--)
          {
            string typeName = CreateTypeNameOf(scopes, c);
            containerTypes.AddRange(FindType(typeName, ignoreTypeCase, modules));
          }

          if (containerTypes.Count > 0)
          {
            return (MemberInfo[])(containerTypes.ToArray());
          }
          else
          {
            containerTypes.Clear();

            string name = scopes[scopes.Length - 1];
            string[] typeScopes = new string[scopes.Length - 1];

            Array.Copy(scopes, typeScopes, typeScopes.Length);

            //Second: Separate the last name as memberName
            for (int c = scopes.Length; c >= 0; c--)
            {
              string typeName = CreateTypeNameOf(typeScopes, c);
              containerTypes.AddRange(FindType(typeName, ignoreTypeCase, modules));
            }

            scopes = null;
            typeScopes = null;

            if (containerTypes.Count > 0)
            {
              List<MemberInfo> members = new List<MemberInfo>();

              MemberInfo[] membersfound = null;
              foreach (Type type in containerTypes)
              {
                membersfound = type.GetMember(name, bindingFlags);
                if (membersfound != null)
                {
                  members.AddRange(membersfound);
                }
              }
              containerTypes.Clear();
              containerTypes = null;

              return members.ToArray();
            }
            else
            {
              return null;
            }
          }
        }
      }
      return null;
    }

    protected static MemberInfo[] FindMemberInfo(string name, string namespacePrefix, string classPrefix, bool ignoreTypeCase, BindingFlags bindingFlags, Module[] modules)
    {

      string typeName = string.Empty;

      if (string.IsNullOrEmpty(namespacePrefix) && string.IsNullOrEmpty(classPrefix))
      {
        typeName = name;
      }
      else if (string.IsNullOrEmpty(namespacePrefix))
      {
        typeName = namespacePrefix + NamespaceSeparator + name;
      }
      else if (string.IsNullOrEmpty(classPrefix))
      {
        typeName = namespacePrefix;
      }
      else
      {
        typeName = namespacePrefix + NamespaceSeparator + classPrefix;
      }

      if (modules != null)
      {
        List<Type> containerTypes = FindType(typeName, ignoreTypeCase, modules);

        if (containerTypes.Count == 1)
        {
          return (MemberInfo[])containerTypes.ToArray(); //Found!
        }
        else
        {
          List<MemberInfo> members = new List<MemberInfo>();

          MemberInfo[] membersfound = null;
          foreach (Type type in containerTypes)
          {
            membersfound = type.GetMember(name, bindingFlags);
            if (membersfound != null)
            {
              members.AddRange(membersfound);
            }
          }
          return members.ToArray();
        }
      }
      return null;
    }
    #endregion
  }
}
